#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <sys/wait.h>

//触摸屏文件
#define TS_PATH  "/dev/input/event0"
//屏幕文件
#define FB_FILE  "/dev/fb0"

//触摸屏文件
int ts_fd;
//屏幕文件
int lcd_fd;

//映射文件指针
unsigned int *mem_p;
//坐标点
int X, Y;


int lcd_init(void);
int lcd_uninit(void);
int show_bmp(const char *pathname);
int get_xy(void);
void show_one(void);


int main(void)
{
    int n = 0; // 状态变量，用于控制程序流程

    
    while (1) 
    {
        // 根据状态变量n来决定执行的流程
        switch (n) 
        {
            case 0:
                // 显示主页面
                show_one();
                n = 1; // 状态变更为1
                break;
            case 1:
                get_xy(); // 获取触摸坐标
                // 检测是否触摸了管理员登录区域
                if (Y < 100 && X > 650) 
                {
                    lcd_init();
                    show_bmp("password.bmp");
                    lcd_uninit();
                    n = 2; // 状态变更为2
                }
                break;
            case 2:
                get_xy(); // 再次获取触摸坐标
                // 检测是否触摸了返回按钮
                if (Y < 100 && X < 100) 
                {
                    n = 0; // 返回主页面
                    break;
                }
                if ( X < 250 && Y > 410) 
                {
                    n = 3;
                    break;
                }
                break;
            case 3:
                get_xy(); // 再次获取触摸坐标
                lcd_init();
                show_bmp("user.bmp");
                lcd_uninit();
                // 检测是否触摸了返回按钮
                if (X > 200 && X < 600 && Y > 410 && Y < 460) 
                {
                    n = 0; // 返回主页面
                    break;
                }
                break;
        }
    }
}

void show_one()
{
    //主页面
    lcd_init();
    show_bmp("theme.bmp");
}

/** 
 * 初始化屏幕文件
 * 
**/
int lcd_init(void)
{
    //打开frame buffer设备文件--屏幕文件
    lcd_fd = open(FB_FILE, O_RDWR);
    if(lcd_fd == -1)
    {
        perror("open error:");
        return -1;
    }

    //屏幕映射
    mem_p = (unsigned int *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
    if(mem_p == MAP_FAILED)
    {
        perror("mmap");
        return -1;
    }

    return 0;
}

/** 
 * 申请内存映射内存
 * 
**/
int lcd_uninit(void)
{
   // 解除映射
    if (munmap(mem_p, 800*480*4) == -1) 
    {
        perror("munmap error:");
        return -1;
    }
    close(lcd_fd);
    return 0;
}

/** 
 * 显示一张800×480的24位bmp图片，并将图片放入内存映射空间
 * 
**/
int show_bmp(const char *pathname)
{
    int bmp_fd, i,j;
    //存储bmp文件的像素点
    unsigned char bmp_buff[800*480*3] = {0};
    //写进内存映射缓冲区的缓冲区
    unsigned int *buff = malloc(800*480*sizeof(unsigned int)); // 使用动态分配的内存

    if (buff == NULL) 
    {
        perror("malloc error:");
        return -1;
    }

    bmp_fd = open(pathname, O_RDONLY);
    if(bmp_fd == -1)
    {
        perror("open");
        free(buff);
        return -1;
    }

    //跳过54个字节头
    lseek(bmp_fd, 54, SEEK_SET);

    //读图片的全部RGB到缓冲区
    if (read(bmp_fd, bmp_buff, sizeof(bmp_buff)) != sizeof(bmp_buff)) 
    {
        perror("read error:");
        free(buff);
        close(bmp_fd);
        return -1;
    }

    //将RGB转换为BGR
    for(i=0; i<800*480; i++)
    {
        buff[i] = (bmp_buff[3*i+2] << 16) | (bmp_buff[3*i+1] << 8) | bmp_buff[3*i+0];//AGRB
    }

    // 像素点填充到屏幕
    for(i = 0; i < 480; i++) // 按行遍历
    { 
        for(j = 0; j < 800; j++) // 按列遍历
        { 
            // 从buff中获取像素数据，确保使用正确的索引
            unsigned int pixel = buff[i * 800 + j]; //i=0 :0 - 799
            
            // 将像素数据复制到帧缓冲区mem_p中
            // 确保使用正确的索引，这里假设mem_p的布局与buff相同
            mem_p[((479 - i) * 800) + j] = pixel;  //479*800 - 479*800+799
        }
    }

    free(buff);
    close(bmp_fd);
    return 0;
}

/** 
 * 获取X Y坐标值
 * 
**/

int get_xy(void)
{
    struct input_event ts;

    ts_fd = open(TS_PATH, O_RDWR);
    if(ts_fd == -1)
    {
        printf("open ts failure\n");
        return -1;
    }

    while(1)
    {
        //松开触摸后，再打印
        while (1)
        {
            read(ts_fd, &ts, sizeof(struct input_event));

            //判断类型
            if(ts.type == EV_ABS && ts.code == ABS_X)
            {
                X = ts.value;
            }

            if(ts.type == EV_ABS && ts.code == ABS_Y)
            {
                Y = ts.value;
            }

            //判断按下
            if(ts.type == EV_KEY && ts.code ==  BTN_TOUCH && ts.value == 1){ }
           
            //判断是否松开
            if(ts.type == EV_KEY && ts.code ==  BTN_TOUCH && ts.value == 0)
            {                                                  	             	
                X = X*(800.0/1024.0);      
                Y = Y*(480.0/600.0);
                break;
            }           
        }
        printf("X:%d, Y:%d\n", X, Y);
        return 0;
    }
}
